#pragma once
#include <xscript/xitemfloat.h>
#include <xscript/xitemint32.h>
#include <xscript/xscriptexecutor.h>
#include <astree/xabstractsyntaxtreen.h>

template <class T>
inline T plus(T a, std::shared_ptr<XItem> item) {
    if (item->asInt32())
        return a + item->asInt32()->getValue();
    else if (item->asFloat())
        return a + item->asFloat()->getValue();
    else
        XScriptExecutor::getInstance()->setError(XError::XError_ArgumentTypeError, item->getItemInfo());
    return 0;
}

template <class T>
inline T minus(T a, std::shared_ptr<XItem> item) {
    if (item->asInt32())
        return a - item->asInt32()->getValue();
    else if (item->asFloat())
        return a - item->asFloat()->getValue();
    else
        XScriptExecutor::getInstance()->setError(XError::XError_ArgumentTypeError, item->getItemInfo());
    return 0;
}

template <class T>
inline T multi(T a, std::shared_ptr<XItem> item) {
    if (item->asInt32())
        return a * item->asInt32()->getValue();
    else if (item->asFloat())
        return a * item->asFloat()->getValue();
    else
        XScriptExecutor::getInstance()->setError(XError::XError_ArgumentTypeError, item->getItemInfo());
    return 0;
}

template <class T>
inline std::tuple<T, bool> div(T a, std::shared_ptr<XItem> item) {
    T b = 0;
    if (item->asFloat())
        b = item->asFloat()->getValue();
    else if (item->asInt32())
        b = item->asInt32()->getValue();

    if (std::fabs(b) < 0E-6)
        return std::make_tuple<T, bool>(0, false);

    return std::make_tuple<T, bool>(a / b, true);
}

class XAbstractSyntaxTreePlus : public XAbstractSyntaxTreeN<2> {
  public:
    XAbstractSyntaxTreePlus(XTokenPtr inputToken):
        XAbstractSyntaxTreeN<2>(inputToken) {
        setName(L"+");
    }

    XAbstractSyntaxTreeType getTreeType()const {return XAbstractSyntaxTreeType_Plus;}
  protected:
    bool invokeImpl(std::shared_ptr<XVariableTable> table);
};

class XAbstractSyntaxTreeMinus : public XAbstractSyntaxTreeN<2> {
  public:
    XAbstractSyntaxTreeMinus(XTokenPtr inputToken):
        XAbstractSyntaxTreeN<2>(inputToken) {
        setName(L"-");
    }

    XAbstractSyntaxTreeType getTreeType()const {return XAbstractSyntaxTreeType_Minus;}
  protected:
    bool invokeImpl(std::shared_ptr<XVariableTable> table);
};

class XAbstractSyntaxTreeMulti : public XAbstractSyntaxTreeN<2> {
  public:
    XAbstractSyntaxTreeMulti(XTokenPtr inputToken):
        XAbstractSyntaxTreeN<2>(inputToken) {
        setName(L"*");
    }

    XAbstractSyntaxTreeType getTreeType()const {return XAbstractSyntaxTreeType_Multi;}
  protected:
    bool invokeImpl(std::shared_ptr<XVariableTable> table);
};

class XAbstractSyntaxTreeDiv : public XAbstractSyntaxTreeN<2> {
  public:
    XAbstractSyntaxTreeDiv(XTokenPtr inputToken):
        XAbstractSyntaxTreeN<2>(inputToken) {
        setName(L"/");
    }

    XAbstractSyntaxTreeType getTreeType()const {return XAbstractSyntaxTreeType_Div;}
  protected:
    bool invokeImpl(std::shared_ptr<XVariableTable> table);
};
